import { DateTim } from "../../components/DateTim";
import { Handler } from "../../components/Handler";
import { LanguageMgr } from "../../components/language/LanguageMgr";
import { LogMgr } from "../../components/LogMgr";
import { chatWsUrl } from "../../env/ApiEnv";
import { DialogViewManager } from "../../managers/DialogViewManager";
import { GlobelDataMgr } from "../../managers/GlobelDataMgr";
import { GlobalEventsMgr, GlobalEventsType } from "../../managers/GlobelEventMgr";
import { GlobelMgr } from "../../managers/GlobelMgr";
import { ReceiveChannelMessageEventEnum, SendChannelMessageEventEnum, SendMessageEventEnum } from "./SocketProtocol";

export enum CloseCode {
    /** 超时 */
    OverTime = 4000,
    /** 验证未通过 -> 重新登录 */
    Unauthorized = 4001,
    /** 异地登录 -> 强制退到登录界面, 清除登录后的所有缓存数据 */
    LoggedElseWhere = 4002,
    /** 用户已禁用 -> 强制退到登录界面, 清除登录后的所有缓存数据 */
    UserBanned = 4003,
    /** 用户删除账号 */
    DeleteAccount = 4004,
    /** 停服维护, 不允许连接*/
    StopServer = 4005,
    /** 停服维护, 强制断线 */
    StopServerLeaveClient =4006
}
export class SocketConnection {
    private _socketID:number//1主socket  2聊天服务器
    private _socket: WebSocket;
    private _callback:Handler;
    private _reconnectTimeoutId:number
    private _reconnectInterval: number = 3;// 重连间隔为3秒
    private _reconnectInx:number;//重连次数
    private _heartbeatFrequency:number = 3;//心跳频率
    private _maxTim:number = 4;//延迟超过多少秒强制重连
    private _heartbeatTimId:number;
    private _timeoutTimID:number;
    private _monitorTimID:number;//监听心跳返回时间timID
    private _codes:Array<number> = [4001,4002,4003,4004,4005,4006];
    private _heartbeatTimeStamp:number;//发送心跳时的时间戳
    private _isReconnectING:boolean;//是否在连接中
    private  _dateTim:DateTim;
    private _isOpen:boolean;//服务器是否在连接状态
    constructor(callback:Handler,socketID:number) {
        this._socketID = socketID;
        this._callback = callback;
        this._dateTim = new DateTim(this.onDateTim.bind(this),1);
    }
    /**
     * 服务器是否是连接状态
     */
    public getIsOpen():boolean{
        return this._isOpen;
    }
    public connect(): void {
        if(GlobelDataMgr.instance.getToken())//如果token异常则不连服务器了
        {
            this.createWebSocket();
        }
    }
    /**主动关闭连接*/
    public close():void{
        this._isOpen = false;
        this.stopHeartbeat();
        this._dateTim.stop();
        if (this._socket) {
            this._socket.onopen = null;
            this._socket.onmessage = null;
            this._socket.onclose = null;
            this._socket.onerror = null;
            this._socket.close();
            this._socket = null;
            this.stopReconnectTimer();
        }
    }
    public sendMessage(event:SendChannelMessageEventEnum | SendMessageEventEnum,valueData?) {
        if (this._socket && this._socket.readyState === WebSocket.OPEN) {
            if(event!= SendChannelMessageEventEnum.Ping)
            {
                console.log("发送协议ID="+event);
                 console.log(valueData);
            }
            let msg ={
                event:event,
                data:valueData
            }
            this._socket.send(JSON.stringify(msg));
            this.startDateTim();
            this.stopHeartbeatTim();
        } else {
            console.error("WebSocket is not open. Cannot send message.");
        }
    }
    private createWebSocket(): void {
            // 如果当前已有连接，则先关闭之前的连接并清除定时器
        if (this._socket) {
            this._socket.onopen = null;
            this._socket.onmessage = null;
            this._socket.onclose = null;
            this._socket.onerror = null;
            this._socket.close();
            this._socket = null;
            this.stopReconnectTimer();
        }
        let wsUrl:string;
        if(this._socketID==1)
        {
            wsUrl = wsUrl
        }else{
            wsUrl = chatWsUrl
        }
       LogMgr.log(this._socketID+"开始连接服务器url="+wsUrl);
        this._isReconnectING = true;
        this._socket = new WebSocket(wsUrl);
        this._socket.onopen = () => {
            this._isReconnectING = false;
           LogMgr.log(this._socketID+"连接服务器成功");
            let data ={
                token:GlobelDataMgr.instance.getToken()
            }
            this.sendMessage(SendChannelMessageEventEnum.Join,data);
            this._reconnectInx=0;
            this.stopReconnectTimer();
        };

        this._socket.onmessage = (event) => {
            this.startHeartbeatTim();
            let delay:number =  Date.now()-this._heartbeatTimeStamp;
            this._dateTim.stop();
            GlobelDataMgr.instance.setNetworkDelay(delay);
            if (event.data == null) {
                 LogMgr.error(`[onWsMessage] received null message`, event);
                return;
            }
            const _message:soketMessage = JSON.parse(event.data);
            if(_message.event!=ReceiveChannelMessageEventEnum.Pong)//心跳不打印
            {
               LogMgr.log(this._socketID+"收到服务器数据ID="+_message.event);
               LogMgr.log(_message);
            }
            if(_message.event==ReceiveChannelMessageEventEnum.RequestFailedInfo)//异常
            {
                 LogMgr.error(this._socketID+"服务器返回异常code="+_message.data.code);
            }else if(_message.event==ReceiveChannelMessageEventEnum.JoinedSuccess){
                GlobelDataMgr.instance.setSocketTimeStamp(_message.data.currentTimestamp);
                this._isOpen = true;
                if(this._socketID==1)
                {
                    GlobalEventsMgr.instance.emit(GlobalEventsType.socketOpen);
                }else{
                    GlobalEventsMgr.instance.emit(GlobalEventsType.chatSocketOpen);
                }
               
            }else{
                this._callback.runWith([this._socketID,_message.event,_message.data]);
            }
        };

        this._socket.onclose = (event) => {
            this._isOpen = false;
            this._dateTim.stop();
            console.log(this._socketID+'WebSocket closed code='+event.code);
            this.stopHeartbeat();
            if(this._codes.indexOf(event.code)==-1)
            {
                if(!this._isReconnectING)
                {
                    this.startReconnectTimer();
                }
            }
            this._isReconnectING = false;
            if(this._socketID==1)
            {
                GlobalEventsMgr.instance.emit(GlobalEventsType.socketClose,event.code);
            }else{
                GlobalEventsMgr.instance.emit(GlobalEventsType.chatSocketOpen,event.code);
            }
        };
        this._socket.onerror = (error) => {
            console.error(this._socketID+'WebSocket error:', error);
            if(!this._isReconnectING)
            {
                this.startReconnectTimer();
            }
            this._isReconnectING = false;
        };
    }
    /**开启监听服务器响应时间*/
    private startDateTim():void{
        this._dateTim.start();
        this._heartbeatTimeStamp = Date.now();
    }
    private startHeartbeatTim():void{
        this._heartbeatTimId = setTimeout(() => {
            this.sendMessage(SendChannelMessageEventEnum.Ping);
        },this._heartbeatFrequency*1000);
    }
    private stopHeartbeatTim():void{
        clearTimeout(this._heartbeatTimId);
    }
    private onDateTim(elapsedTime:number){
        if(elapsedTime>this._maxTim)
        {
            this.forceDisconnectionReconnection();
        }
    }
    public forceDisconnectionReconnection():void{
        this.close();//强制断开并重连
        this.stopHeartbeatTim();
        this.startReconnectTimer();
    }
    private stopHeartbeat():void{
        clearTimeout(this._heartbeatTimId);
    }
    
    private startReconnectTimer(): void {
        console.log(this._socketID+"开始断线重连");
        if(this._socketID==1)
        {
            console.log("打开菊花");
        }
        this._reconnectTimeoutId = setTimeout(() => {
            if(this._reconnectInx==2)
            {
                this.stopReconnectTimer();
                const str = LanguageMgr.instance.getString("text_not_network");
            }else{
                this.createWebSocket(); // 尝试重新连接
                this._reconnectInx++
            }
        }, this._reconnectInterval*1000);
    }
    private stopReconnectTimer(): void {
        if (this._reconnectTimeoutId) {
            if(this._socketID==1)
            {
               console.log("关闭菊花");
               
            }
            console.log('Clearing reconnect timer.');
            clearTimeout(this._reconnectTimeoutId);
            this._reconnectTimeoutId = null;
        }
    }
}
type soketMessage = {
    event:ReceiveChannelMessageEventEnum
    data:any;
};